home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / sndhrdw / llander.c < prev    next >
C/C++ Source or Header  |  2000-04-23  |  8KB  |  284 lines

  1. /***************************************************************************
  2.  
  3.   Lunar Lander Specific Sound Code
  4.  
  5. ***************************************************************************/
  6.  
  7. #include "driver.h"
  8.  
  9. /* Variables for the lander custom sound support */
  10.  
  11. #define MIN_SLICE 10
  12. #define LANDER_OVERSAMPLE_RATE    768000
  13.  
  14. #define AUDIO_CONV16(A) ((A)-0x8000)
  15.  
  16. static int sinetable[64]=
  17. {
  18.     128,140,153,165,177,188,199,209,218,226,234,240,245,250,253,254,
  19.     255,254,253,250,245,240,234,226,218,209,199,188,177,165,153,140,
  20.     128,116,103, 91, 79, 68, 57, 47, 38, 30, 22, 16, 11,  6,  3,  2,
  21.     1  ,2  ,3  ,  6, 11, 16, 22, 30, 38, 47, 57, 68, 79, 91,103,116
  22. };
  23.  
  24. static int llander_volume[8]={0x00,0x20,0x40,0x60,0x80,0xa0,0xc0,0xff};
  25. static int buffer_len;
  26. static int emulation_rate;
  27. static long multiplier;
  28. static int sample_pos;
  29. static int channel;
  30. static int lfsr_index;
  31. static INT16 *sample_buffer;
  32. static unsigned short *lfsr_buffer;
  33.  
  34. static int volume;
  35. static int tone_6khz;
  36. static int tone_3khz;
  37. static int llander_explosion;
  38.  
  39. int llander_sh_start(const struct MachineSound *msound)
  40. {
  41.     int loop,lfsrtmp,nor1,nor2,bit14,bit6;
  42.     long fraction,remainder;
  43.  
  44.         /* Dont initialise if no sound system */
  45.         if (Machine->sample_rate == 0) return 0;
  46.  
  47.     /* Initialise the simple vars */
  48.  
  49.     volume=0;
  50.     tone_3khz=0;
  51.     tone_6khz=0;
  52.     llander_explosion=0;
  53.  
  54.     buffer_len = Machine->sample_rate / Machine->drv->frames_per_second;
  55.     emulation_rate = buffer_len * Machine->drv->frames_per_second;
  56.     sample_pos = 0;
  57.  
  58.     /* Calculate the multipler to convert output sample number to the oversample rate (768khz) number */
  59.     /* multipler is held as a fixed point number 16:16                                                */
  60.  
  61.     multiplier=LANDER_OVERSAMPLE_RATE/(long)emulation_rate;
  62.     remainder=multiplier*LANDER_OVERSAMPLE_RATE;
  63.     fraction=remainder<<16;
  64.     fraction/=emulation_rate;
  65.  
  66.     multiplier=(multiplier<<16)+fraction;
  67.  
  68. //    logerror("LANDER: Multiplier=%lx remainder=%lx fraction=%lx rate=%x\n",multiplier,remainder,fraction,emulation_rate);
  69.  
  70.     /* Generate the LFSR lookup table for the lander white noise generator */
  71.  
  72.     lfsr_index=0;
  73.     if ((lfsr_buffer = malloc(65536*2)) == 0) return 1;
  74.  
  75.     for(loop=0;loop<65536;loop++)
  76.     {
  77.         /* Calc next LFSR value from current value */
  78.  
  79.         lfsrtmp=(short)loop<<1;
  80.  
  81.         bit14=(loop&0x04000)?1:0;
  82.         bit6=(loop&0x0040)?1:0;
  83.  
  84.         nor1=(!( bit14 &&  bit6 ) )?0:1;            /* Note the inversion for the NOR gate */
  85.         nor2=(!(!bit14 && !bit6 ) )?0:1;
  86.         lfsrtmp|=nor1|nor2;
  87.  
  88.         lfsr_buffer[loop]=lfsrtmp;
  89.  
  90. //        logerror("LFSR Buffer: %04x    Next=%04x\n",loop, lfsr_buffer[loop]);
  91.     }
  92.  
  93.     /* Allocate channel and buffer */
  94.  
  95.     channel = mixer_allocate_channel(25);
  96.  
  97.     if ((sample_buffer = malloc(sizeof(INT16)*buffer_len)) == 0) return 1;
  98.     memset(sample_buffer,0,sizeof(INT16)*buffer_len);
  99.  
  100.     return 0;
  101. }
  102.  
  103. void llander_sh_stop(void)
  104. {
  105. }
  106.  
  107.  
  108. /***************************************************************************
  109.  
  110.   Sample Generation code.
  111.  
  112.   Lander has 4 sound sources: 3khz, 6khz, thrust, explosion
  113.  
  114.   As the filtering removes a lot of the signal amplitute on thrust and
  115.   explosion paths the gain is partitioned unequally:
  116.  
  117.   3khz (tone)             Gain 1
  118.   6khz (tone)             Gain 1
  119.   thrust (12khz noise)    Gain 2
  120.   explosion (12khz noise) Gain 4
  121.  
  122.   After combining the sources the output is scaled accordingly. (Div 8)
  123.  
  124.   Sound generation is done by oversampling (x64) of the signal to remove the
  125.   need to interpolate between samples. It gives the closest point of the
  126.   sample point to the real signal, there is a small error between the two, the
  127.   higher the oversample rate the lower the error.
  128.  
  129.                                          oversample_rate
  130.      oversample_number = sample_number * ---------------
  131.                                          sample_rate
  132.  
  133.      e.g for sample rate=44100 hz and oversample_rate=768000 hz
  134.  
  135.      oversample_number = sample_number * 17.41487
  136.  
  137.   The calculations are all done in fixed point 16.16 format. The oversample is
  138.   mapped to the sinewave in the following manner
  139.  
  140.      e.g for 3khz (12khz / 4)
  141.  
  142.      sine point = ( oversample_number / 4 ) & 0b00111111
  143.  
  144.      this coverts the oversample down to 3khz x 64 then wraps the buffer mod
  145.      64 to give the sample point.
  146.  
  147.   The oversample rate chosen in lander is 12khz * 64 = 768khz as 12khz is a
  148.   binary multiple of the all the frequencies involved.
  149.  
  150.   The noise generation is done by linear feedback shift register which I've
  151.   modelled with an array, the array value at the current index points to the
  152.   next index to be used, the table is precalulated at startup.
  153.  
  154.   The output of noise is taken evertime we cross a 12khz boundary, the code
  155.   then sets a target value (noisetarg), we then scan the gap between the last
  156.   oversample point and the current oversample point at the oversample rate
  157.   using the following algorithm:
  158.  
  159.     noisecurrent = noisecurrent + (noisetarg-noisecurrent) * small_value
  160.  
  161.     (currently small value = 1/256)
  162.  
  163.   again this is done in fixed point 16.16 and results in the smoothing of the
  164.   output waveform which reduces the high frequency noise. It also reduces the
  165.   overall amplitude swing of the output, hence the gain partitioning.
  166.  
  167.   You could probably argue that the oversample rate could be dropped without
  168.   any loss in quality and would recude the cpu load, but lander is hardly a cpu
  169.   hog.
  170.  
  171.   The outputs from all of the above are then added and scaled up/down to a single
  172.   sample
  173.  
  174.   K.Wilkins 13/5/98
  175.  
  176. ***************************************************************************/
  177.  
  178. void llander_process(INT16 *buffer,int start, int n)
  179. {
  180.     static int sampnum=0;
  181.     static long noisetarg=0,noisecurrent=0;
  182.     static long lastoversampnum=0;
  183.     int loop,sample;
  184.     long oversampnum,loop2;
  185.  
  186.     for(loop=0;loop<n;loop++)
  187.     {
  188.         oversampnum=(long)(sampnum*multiplier)>>16;
  189.  
  190. //        logerror("LANDER: sampnum=%x oversampnum=%lx\n",sampnum, oversampnum);
  191.  
  192.         /* Pick up new noise target value whenever 12khz changes */
  193.  
  194.         if(lastoversampnum>>6!=oversampnum>>6)
  195.         {
  196.             lfsr_index=lfsr_buffer[lfsr_index];
  197.             noisetarg=(lfsr_buffer[lfsr_index]&0x4000)?llander_volume[volume]:0x00;
  198.             noisetarg<<=16;
  199.         }
  200.  
  201.         /* Do tracking of noisetarg to noise current done in fixed point 16:16    */
  202.         /* each step takes us 1/256 of the difference between desired and current */
  203.  
  204.         for(loop2=lastoversampnum;loop2<oversampnum;loop2++)
  205.         {
  206.             noisecurrent+=(noisetarg-noisecurrent)>>7;    /* Equiv of multiply by 1/256 */
  207.         }
  208.  
  209.         sample=(int)(noisecurrent>>16);
  210.         sample<<=1;    /* Gain = 2 */
  211.  
  212.         if(tone_3khz)
  213.         {
  214.             sample+=sinetable[(oversampnum>>2)&0x3f];
  215.         }
  216.         if(tone_6khz)
  217.         {
  218.             sample+=sinetable[(oversampnum>>1)&0x3f];
  219.         }
  220.         if(llander_explosion)
  221.         {
  222.             sample+=(int)(noisecurrent>>(16-2));    /* Gain of 4 */
  223.         }
  224.  
  225.         /* Scale ouput down to buffer */
  226.  
  227.         buffer[start+loop] = AUDIO_CONV16(sample<<5);
  228.  
  229.         sampnum++;
  230.         lastoversampnum=oversampnum;
  231.     }
  232. }
  233.  
  234.  
  235. void llander_sh_update_partial(void)
  236. {
  237.     int newpos;
  238.  
  239.     if (Machine->sample_rate == 0) return;
  240.  
  241.     newpos = sound_scalebufferpos(buffer_len); /* get current position based on the timer */
  242.  
  243.     if(newpos-sample_pos<MIN_SLICE) return;
  244.  
  245.     /* Process count samples into the buffer */
  246.  
  247.     llander_process (sample_buffer, sample_pos, newpos - sample_pos);
  248.  
  249.     /* Update sample position */
  250.  
  251.     sample_pos = newpos;
  252. }
  253.  
  254.  
  255. void llander_sh_update(void)
  256. {
  257.     if (Machine->sample_rate == 0) return;
  258.  
  259.     if (sample_pos < buffer_len)
  260.         llander_process (sample_buffer, sample_pos, buffer_len - sample_pos);
  261.     sample_pos = 0;
  262.  
  263.     mixer_play_streamed_sample_16(channel,sample_buffer,2*buffer_len,emulation_rate);
  264. }
  265.  
  266. WRITE_HANDLER( llander_snd_reset_w )
  267. {
  268.         lfsr_index=0;
  269. }
  270.  
  271. WRITE_HANDLER( llander_sounds_w )
  272. {
  273.     /* Update sound to present */
  274.     llander_sh_update_partial();
  275.  
  276.     /* Lunar Lander sound breakdown */
  277.  
  278.     volume    = data & 0x07;
  279.     tone_3khz = data & 0x10;
  280.     tone_6khz = data & 0x20;
  281.     llander_explosion = data & 0x08;
  282. }
  283.  
  284.